// Fill out your copyright notice in the Description page of Project Settings.


#include "MyAlgorithm.h"
#include <windows.h>
#include <Async/Async.h>
#include <time.h>
#include <random>

MyAlgorithm::MyAlgorithm()
{
}

MyAlgorithm::~MyAlgorithm()
{
}

void MyAlgorithm::algorithm_primary(AActor* tank) {
	FVector location = tank->GetActorLocation();
	int count = 0;
	srand(time(NULL));
	while (count <= 20) {
		UE_LOG(LogTemp, Warning, TEXT("location x is %f, location y is %f"), location.X, location.Y);
		FVector des(rand() % 1500 + 200, rand() % 1500 + 200, location.Z);
		tankMove(tank, location, des);
		count++;
	}
}

void MyAlgorithm::algorithm_second(AActor* tank) {
	int count = 0;
	FVector location = tank->GetActorLocation();
	std::mt19937 generator(std::random_device().entropy());
	std::uniform_int_distribution<int> distribution(200, 1700);
	while (count <= 20) {
		FVector des(distribution(generator), distribution(generator), location.Z);
		tankMove(tank, location, des);
		count++;
	}
}

void MyAlgorithm::algorithm_third(AActor* tank) {
	FVector location = tank->GetActorLocation();
	int count = 0;
	while (count <= 10) {
		int position[4][2] = { {200, 1800}, {1800, 1800}, {1800, 200}, {200, 200} };
		UE_LOG(LogTemp, Warning, TEXT("location x is %f, location y is %f"), location.X, location.Y);
		FVector des(position[count % 4][0], position[count % 4][1], location.Z);
		tankMove(tank, location, des);
		count++;
	}
}

void MyAlgorithm::algorithm_forth(AActor* tank) {
	FVector location = tank->GetActorLocation();
	int count = 0;
	srand(time(NULL) + 1000);
	while (count <= 20) {
		UE_LOG(LogTemp, Warning, TEXT("location x is %f, location y is %f"), location.X, location.Y);
		FVector des(rand() % 1500 + 200, rand() % 1500 + 200, location.Z);
		tankMove(tank, location, des);
		count++;
	}
}

void MyAlgorithm::tankMoveTest(AActor* tank, FVector& start, FVector& end) {
	AsyncTask(ENamedThreads::GameThread, [tank, end]()
		{
			tank->SetActorLocation(end);
	});
}

void MyAlgorithm::tankMove(AActor* tank, FVector & start, FVector & end) {
	int x, y;
	x = end.X - start.X;
	y = end.Y - start.Y;
	if (x == 0 && y == 0) {
		return;
	}
	while (x != 0 || y != 0) {
		UE_LOG(LogTemp, Warning, TEXT("x is %d, y is %d"), x, y);
		if (x == 0) {
			if (abs(y) > speed) {
				if (y > 0) {
					start.Y += speed;
					y -= speed;
				}
				else {
					start.Y -= speed;
					y += speed;
				}
				Sleep(30);
				setLocation(tank, start);
			}
			else {
				start.Y += y;
				Sleep(30);
				setLocation(tank, start);
				y = 0;
			}
		}
		else {
			if (y == 0) {
				if (abs(x) > speed) {
					if (x > 0) {
						start.X += speed;
						x -= speed;
					}
					else {
						start.X -= speed;
						x += speed;
					}
					Sleep(30);
					setLocation(tank, start);
				}
				else {
					start.X += x;
					Sleep(30);
					setLocation(tank, start);
					x = 0;
				}
			}
			else {
				if (abs(x) > speed) {
					if (x > 0) {
						start.X += speed;
						x -= speed;
					}
					else {
						start.X -= speed;
						x += speed;
					}
					if (abs(y) > speed) {
						if (y > 0) {
							start.Y += speed;
							y -= speed;
						}
						else {
							start.Y -= speed;
							y += speed;
						}
						Sleep(30);
						setLocation(tank, start);
					}
					else {
						start.Y += y;
						y = 0;
						Sleep(30);
						setLocation(tank, start);
					}
				}
				else {
					start.X += x;
					x = 0;
					if (abs(y) > speed) {
						if (y > 0) {
							start.Y += speed;
							y -= speed;
						}
						else {
							start.Y -= speed;
							y += speed;
						}
						Sleep(30);
						setLocation(tank, start);
					}
					else {
						start.Y += y;
						x = 0;
						y = 0;
						Sleep(30);
						setLocation(tank, start);
					}
				}
			}
		}
	}
	UE_LOG(LogTemp, Warning, TEXT("exit tankMove"));
}

void MyAlgorithm::setLocation(AActor* tank, FVector & location) {
	if (!tank->IsValidLowLevel()) {
		return;
	}
	location.Z = tank->GetActorLocation().Z;
	AsyncTask(ENamedThreads::GameThread, [tank, location]()
	{
		if (tank->IsValidLowLevel()) {
			tank->SetActorLocationAndRotation(location, CalculateRotationFromCoordinates(tank->GetActorLocation(), location));
		}
	});
}

FRotator MyAlgorithm::CalculateRotationFromCoordinates(const FVector& PreviousCoordinate, const FVector& CurrentCoordinate)
{
	// 1. 计算从PreviousCoordinate到CurrentCoordinate的向量
	FVector DirectionVector = CurrentCoordinate - PreviousCoordinate;

	// 2. 计算向量在水平面上（XY平面）的投影向量，用于确定绕Z轴的旋转角度
	FVector HorizontalProjection = FVector(DirectionVector.X, DirectionVector.Y, 0.0f);

	// 3. 计算绕Z轴的旋转角度
	float ZRotation = FMath::RadiansToDegrees(FMath::Atan2(HorizontalProjection.Y, HorizontalProjection.X));

	// 4. 计算向量的长度（模），用于后续判断是否为零向量
	float VectorLength = DirectionVector.Size();

	// 5. 如果向量长度不为零，计算绕X轴和Y轴的旋转角度
	if (VectorLength > 0.0f)
	{
		// 计算向量与垂直方向（Z轴）的夹角，用于确定绕X轴的旋转角度
		float XRotation = FMath::RadiansToDegrees(FMath::Atan2(DirectionVector.Z, HorizontalProjection.Size()));

		// 计算向量在垂直平面（YZ平面）上的投影向量，用于确定绕Y轴的旋转角度
		FVector VerticalProjection = FVector(0.0f, DirectionVector.Y, DirectionVector.Z);

		// 计算绕Y轴的旋转角度
		float YRotation = FMath::RadiansToDegrees(FMath::Atan2(VerticalProjection.Z, VerticalProjection.Y));

		// 返回计算得到的旋转信息
		return FRotator(0, ZRotation, 0);
	}
	else
	{
		// 如果是零向量，返回默认的旋转信息（这里可以根据具体需求设置，比如零旋转）
		return FRotator(0.0f, 0.0f, 0.0f);
	}
}
